package com.cy.stone.framework.web.advice;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import com.cy.stone.common.annotation.Encrypt;
import com.cy.stone.common.properties.EncryptProperties;
import com.cy.stone.common.utils.JacksonUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@ControllerAdvice
@ConditionalOnProperty(prefix = "stone.encrypt", name = "enable", havingValue = "true")
@RequiredArgsConstructor
public class EncryptResponseAdvice implements ResponseBodyAdvice<Object> {

    private final EncryptProperties encryptProperties;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        response.getHeaders().add("requestId", request.getHeaders().getFirst("requestId"));
        response.getHeaders().add("resTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        Encrypt en = supportDecryptRequest(returnType);
        if (en != null) {
            String key = "E1hLu5SQHhI3iFsMsv40Sw==";
            // 将结果用AES key加密
            AES aes = new AES("ECB", "PKCS7Padding", key.getBytes());
            String bodyJson = JacksonUtils.object2String(body);
            String encrypt = aes.encryptBase64(bodyJson, "UTF-8").replaceAll(System.lineSeparator(), "");

            // 将AES key加密
            String publicKey = encryptProperties.getPublicKey();
            RSA rsa = new RSA(null, publicKey);
            String secretKey = rsa.encryptBase64(key, KeyType.PublicKey);
            response.getHeaders().add("secretKey", secretKey);

            return encrypt;
        } else {
            return body;
        }
    }

    private Encrypt supportDecryptRequest(MethodParameter methodParameter) {
        //判斷class是否存在注解
        Encrypt encrypt = methodParameter.getContainingClass().getAnnotation(Encrypt.class);
        if (encrypt != null) {
            return encrypt;
        }
        //判斷方法是否存在注解
        return methodParameter.getMethodAnnotation(Encrypt.class);
    }
}
